/**
 * @(#)NoneedLoginUserServiceImpl.java 2017年5月22日
 * Copyright(C) 2017 ZHEXIN IT CO.,LTD. All rights reserved.
 */
package org.jsbd.boss.service.impl;

import org.jsbd.boss.common.ExportExcel;
import org.jsbd.boss.common.redis.RedisClient;
import org.jsbd.boss.dao.IAddUserRecordDAO;
import org.jsbd.boss.dao.IReserveAddDataUserEmailDAO;
import org.jsbd.boss.dao.ISimulatorLogDAO;
import org.jsbd.boss.dao.IUserClientInfoDAO;
import org.jsbd.boss.domian.NewUserTaskVo;
import org.jsbd.boss.domian.TaskVo;
import org.jsbd.boss.domian.channel.*;
import org.jsbd.boss.enums.LoginTypeEnum;
import org.jsbd.boss.enums.TaskActionEnum;
import org.jsbd.boss.enums.TaskStatusEnum;
import org.jsbd.boss.enums.TaskTypeEnum;
import org.jsbd.boss.service.*;
import org.jsbd.boss.util.BeanCopierUtil;
import org.jsbd.boss.util.CacheKey;
import org.jsbd.boss.util.DateUtil;
import org.jsbd.boss.util.EmailSslUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 预留用户执行新增服务
 * 
 * @author <a href="mailto:xupengcheng@zhexinit.com" >徐鹏程</a>
 * @version 1.0.0
 */
@Service("reserveAddUserService")
public class ReserveAddUserServiceImpl implements IReserveAddUserService {
	public static final Logger LOGGER = LoggerFactory.getLogger(ReserveAddUserServiceImpl.class);

	@Resource
	private SimulatorManager simulatorManager;
	@Resource
	private IAddUserRecordDAO addUserRecordDAO;

	@Resource
	private IChannelApkInfoService channelApkInfoService;
	@Resource
	private IUserClientInfoDAO userClientInfoDAO;
	@Resource
	private RedisClient redisClient;

	private int MAXSIZE = 20;
	@Resource
	private CacheParamManager cacheParamManager;

	@Resource
	private ISimulatorLogDAO simulatorLogDAO;

	@Resource
	private IUserClientInfoService clientInfoService;

	@Resource
	private IReserveAddDataUserEmailDAO reserveAddDataUserEmailDAO;

	@Resource(name = "newTaskService")
	private INewTaskService newTaskService;

	@Resource
	private TaskLuaManager taskLuaManager;

	@Resource
	private IApkSimulatorService apkSimulatorService;

	private EmailSslUtils emailUtil = new EmailSslUtils();

	@Override
	public void initReserveAddTask() {
		try {
			String userTotalKey = CacheKey.RESERVE_USER_TOTAL + DateUtil.getDaysOfTime();
			List<AddReserveRecordVo> marks = (List<AddReserveRecordVo>) redisClient.get(userTotalKey);
			if (marks == null) {
				marks = addUserRecordDAO.selectMarks();
				redisClient.put(userTotalKey, marks, 300);
			}
			Object refreshTime = cacheParamManager.getParamValue(CacheKey.T_L_REFRESH);
			long expireTime = 3;
			if (refreshTime != null) {
				expireTime = Long.parseLong(refreshTime.toString());
			}
			for (AddReserveRecordVo recordVo : marks) {
				String apk = recordVo.getMark();
				String lockKey = CacheKey.R_A_U_T_LOCK + apk;
				String ver = apkSimulatorService.getVer(apk);
				if (redisClient.evalSetNx(lockKey, expireTime)) {
					Integer total = recordVo.getTotal();
					String execTotalKey = CacheKey.RESERVE_ADD_USER_RECORD + DateUtil.getDaysOfTime();
					String execTotal = redisClient.evalHget(execTotalKey, apk);
					int leftNum = total;
					if (execTotal != null) {
						leftNum = total - Integer.parseInt(execTotal);
					}
					if (leftNum > 0) {
						Integer[] queueSizes = taskLuaManager.getQueueSize(new String[] { CacheKey.VER_TASK_QUEUE + ver });
						Integer maxSize = simulatorManager.getApkCanUseSimulator(apk);
						if (maxSize == null) {
							// 默认5个
							maxSize = 5;
						}
						int needSize = maxSize - queueSizes[0];
						int size = 0;
						if (needSize > 0) {
							if (needSize > leftNum) {
								needSize = leftNum;
							}
							while (needSize > 0) {
								UserClientInfo userVo = selectUser(apk);
								if (userVo == null) {
									break;
								}
								userVo.setMark(apk);
								TaskVo taskVo = initTaskVo(userVo);
								if (taskVo != null) {
									TaskStatusEnum status = newTaskService.addReserveTask(taskVo);
									if (status == TaskStatusEnum.SUCCESS) {
										size++;
										needSize--;
									} else {
										String queueKey = CacheKey.RESERVE_ADD_USER_LIST + apk + DateUtil.getDaysOfTime();
										redisClient.putToQueue(queueKey, userVo);
										redisClient.expire(queueKey, DateUtil.leftTimeToMidNight());
										LOGGER.warn("更新预留用户 apk {} queueSize {} imsi {} status {} 添加任务失败", new Object[] { apk, queueSizes[0], userVo.getImsi(), status });
									}
								}
							}
						}
						if (size > 0) {
							redisClient.evalHincrby(execTotalKey, apk, size, DateUtil.leftTimeToMidNight() / 1000);
						}
					}

					redisClient.remove(lockKey);
				}

			}
		} catch (Exception e) {
			LOGGER.error("initReserveAddTask", e);
		}

	}

	private TaskVo initTaskVo(UserClientInfo userVo) {
		String apk = userVo.getMark();
		ChannelApkConfig apkConfig = channelApkInfoService.selectChannelApkConfig(apk);
		if (apkConfig != null) {
			NewUserTaskVo taskVo = new NewUserTaskVo();
			BeanCopierUtil.UserClientInfo2TaskVoBeanCopier.copy(userVo, taskVo, null);
			taskVo.setBase(apkConfig.getBase());
			taskVo.setApkId(apkConfig.getId());
			taskVo.setAddScriptPath(apkConfig.getAddScriptPath());
			taskVo.setAddJarPath(apkConfig.getAddJarPath());
			taskVo.setRegisterActivity(apkConfig.getRegisterActivity());
			taskVo.setApkPath(apkConfig.getApkPath());
			taskVo.setFileFilter(apkConfig.getFileFilter());
			taskVo.setActionType(TaskActionEnum.SEND_TASK.getType());
			taskVo.setTaskType(TaskTypeEnum.ADD_TASK.getType());
			taskVo.setMark(apkConfig.getMark());
			taskVo.setLoginType(LoginTypeEnum.OFFLINE.getType());
			taskVo.setCarrier(ClientManager.checkImsi(userVo.getImsi()));
			return taskVo;
		}
		return null;
	}

	private UserClientInfo selectUser(String mark) {
		String queueKey = CacheKey.RESERVE_ADD_USER_LIST + mark + DateUtil.getDaysOfTime();
		UserClientInfo user = (UserClientInfo) redisClient.pollFromQueue(queueKey);
		if (user == null) {
			AddReserveRecordVo record = new AddReserveRecordVo();
			Integer rd = Integer.parseInt(DateUtil.getCurrentDateStr());
			record.setRd(rd);
			record.setMark(mark);
			Object maxCacheLength = cacheParamManager.getParamValue(CacheKey.USER_CACHE_LENGTH);
			if (maxCacheLength != null) {
				MAXSIZE = Integer.parseInt(maxCacheLength.toString());
			}
			record.setLength(MAXSIZE);
			List<AddReserveRecordVo> userList = addUserRecordDAO.selectRecordList(record);
			if (userList != null && userList.size() > 0) {
				List<UserClientInfo> users = new ArrayList<UserClientInfo>();
				for (int i = 0; i < userList.size(); i++) {
					AddReserveRecordVo recordVo = userList.get(i);
					recordVo.setRd(rd);
					QueryUserClientVo queryUserVo = new QueryUserClientVo();
					queryUserVo.setImsi(recordVo.getImsi());
					Integer carrier = ClientManager.checkImsi(recordVo.getImsi());
					queryUserVo.setCarrier(carrier);
					queryUserVo.setProvince(recordVo.getProvinceId());
					UserClientInfo userVo = userClientInfoDAO.selectClientInfo(queryUserVo);
					if (userVo != null) {
						if (i == 0) {
							user = userVo;
						} else {
							users.add(userVo);
						}
					}
				}
				addUserRecordDAO.batchUpdateRecords(userList);
				if (users.size() > 0) {
					redisClient.putToQueue(queueKey, users.toArray(new UserClientInfo[0]));
					redisClient.expire(queueKey, DateUtil.leftTimeToMidNight());
				}
			}
		}
		return user;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.jsbd.boss.service.IReserveAddUserService#getReserveAddUserList(java
	 * .lang.String)
	 */
	@Override
	public List<ReserveUserVo> getReserveAddUserList(String mark) {
		List<ReserveUserVo> userList = simulatorLogDAO.selectReserveUserList(mark);
		String preDay = DateUtil.getPreSomeDay(2);
		for (ReserveUserVo userVo : userList) {
			UserClientInfo userClient = clientInfoService.selectClientInfo(userVo.getImsi(), userVo.getProvinceId());
			if (userClient != null) {
				userVo.setHsman(userClient.getHsman());
				userVo.setHstype(userClient.getHstype());
				userVo.setImei(userClient.getImei());
				userVo.setRd(preDay);
			}
		}
		return userList;
	}

	@Override
	public void sendReserveAddUserDataEmail() {
		try {
			List<ReserveUserEmail> sendToList = reserveAddDataUserEmailDAO.selectUserList(null);
			Map<String, List<String>> apkUserListMap = new HashMap<String, List<String>>();
			if (sendToList != null && sendToList.size() > 0) {
				for (int i = 0; i < sendToList.size(); i++) {
					ReserveUserEmail user = sendToList.get(i);
					String mark = user.getMark().trim();
					List<String> emails = apkUserListMap.get(mark);
					if (emails == null) {
						emails = new ArrayList<>();
					}
					emails.add(user.getEmail());
					apkUserListMap.put(mark, emails);
				}
			}
			String[] apks = apkUserListMap.keySet().toArray(new String[0]);
			for (String apk : apks) {
				List<ReserveUserVo> userList = getReserveAddUserList(apk);
				if (userList != null && userList.size() > 0) {
					emailUtil.setTo(apkUserListMap.get(apk).toArray(new String[0]));
					emailUtil.setSubject(DateUtil.getCurrentDateTime() + "预安装用户");
					emailUtil.setContent("HI, 数据见附件！");
					String attachment = "/tmp/report/" + apk.substring(apk.indexOf("-") + 1) + DateUtil.getCurrentDateTime() + ".xls";
					ExportExcel<ReserveUserVo> excel = new ExportExcel<>();
					String[] heads = { "日期", "imei", "机型", "品牌", "imsi" };
					excel.exportMultiSheetExcel2003(0, "预安装用户", heads, userList, attachment, "yyyy-MM-dd");
					LOGGER.info("生成预安装用户数据 {}", attachment);
					emailUtil.setAttchmentFileList(new String[] { attachment });
					emailUtil.send();
				}
			}
		} catch (Exception e) {
			LOGGER.error("邮件发送错误!!!", e);
		}
	}

}
